<%-- Copyright (c) 2010 Canadensys --%>
<%@ page import="java.util.ArrayList" %>
<%@ page import="java.util.HashMap" %>
<%@ page import="java.util.List" %>
<%@ page import="java.util.Vector" %>
<%@ page import="net.canadensys.dataportal.vascan.Distribution" %>
<%@ page import="net.canadensys.dataportal.vascan.Habit" %>
<%@ page import="net.canadensys.dataportal.vascan.Lookup" %>
<%@ page import="net.canadensys.dataportal.vascan.Taxon" %>
<%@ page import="net.canadensys.dataportal.vascan.TaxonManager" %>
<%@ page import="net.canadensys.dataportal.vascan.VernacularName" %>
<%@ page import="net.canadensys.dataportal.vascan.utils.LabelMappings" %>
<%@ page import="net.canadensys.dataportal.vascan.predicates.*" %>
<%@ page import="net.canadensys.dataportal.utils.*" %>
<%@ page import="net.canadensys.dataportal.vascan.config.ApplicationConfig" %>
<%@ page import="org.apache.commons.collections.iterators.FilterIterator" %>
<%@ include file="_inc/functions.jsp" %>
<%  String TEMPLATE_PATH = "/taxon.ftl"; %>
<%@ include file="_inc/ftl/processStart.jsp" %>
<%
try{
	/*
	 * Taxon permalink ;
	 * This page will display all available information for an accepted taxon,
	 * or will display only base (name, rank, status, authority...) information in 
	 * case of an synonym taxon. 
	 */

    // data hashmap that will be passed on to root document for display in .ftl
    HashMap<String,Object> data = new HashMap<String,Object>();
	 
	// request id parameter in url
    int id = 0;
   	try{
	    if(request.getParameter("id") != null){
	        id = Integer.valueOf(request.getParameter("id"));
	    }
   	}
    catch(NumberFormatException nfe){
    	System.out.println("###Unparsable id, URL : " + request.getRequestURL().toString() + "###");
    }
    
    // instantiate taxon via hibernate session ; ObjectNotFoundException
    // will pick up the exception in case id is still 0 or if supplied id
    // is invalid
    Taxon taxon = (Taxon) hibernateSession.load(Taxon.class,id);
    if(taxon != null)
        data.put("taxonId",taxon.getId());
    
	// is the taxon concept a synonym
	boolean isSynonymConcept = false;
	
	// is he taxon concept an hybrid
	// the state of isHybridConcept is determined by inspecting the taxon
	// full scientific name for the presence of "x" (multiply sign); this
	// is acheived by the method isHybird() in Taxon; The hybrid status
	// cannot be determined by the presence of hybrid parents because
	// they are sometimes unknown (no entry in database for hybdridparent1 and
    // hybridparent1, but we know that it's an hybrid, because someone said so.
	boolean isHybridConcept = false;
    
    // hybrid parents
    Vector<HashMap<String,Object>> taxonHybridParents = new Vector<HashMap<String,Object>>();
    List<Taxon> hybridParents = null;
    hybridParents = taxon.getHybridparents();
    if(hybridParents != null){
    	if(hybridParents.size() > 0)
    	    isHybridConcept = true;
        for(Taxon hybridParent : hybridParents){
            HashMap<String,Object> hybridParentInfo = new HashMap<String,Object>();
            try{
            	hybridParentInfo.put("taxonId",hybridParent.getId());
                hybridParentInfo.put("fullScientificName",hybridParent.getLookup().getCalnamehtmlauthor());
                hybridParentInfo.put("status",hybridParent.getStatus().getStatus());
                taxonHybridParents.add(hybridParentInfo);
            }
            catch(NullPointerException e){
                //drop on error
            }
        }
    }
    data.put("hybridParents",taxonHybridParents);    
    
    // parents ; it is accepted that a taxon has only one parent, but this
    // is not a rule and some exceptions may occur with synonyms. To prevent
    // errors, the getParent() method of a txon returns a list of most of 
    // the time one element...
    Vector<HashMap<String,Object>> taxonParents = new Vector<HashMap<String,Object>>();
    List<Taxon> parents= null;
    parents = taxon.getParents();
    if(parents != null){
        for(Taxon parent : parents){
            HashMap<String,Object> parentInfo = new HashMap<String,Object>();
            try{
            	parentInfo.put("taxonId",parent.getId());
                parentInfo.put("fullScientificName",parent.getLookup().getCalnamehtmlauthor());
                parentInfo.put("rank",parent.getRank().getRank());
                parentInfo.put("reference",parent.getReference().getReference());
                parentInfo.put("referenceShort",parent.getReference().getReferenceshort());
                parentInfo.put("link",parent.getReference().getUrl());
                taxonParents.add(parentInfo);
            }
            catch(NullPointerException e){
                //drop on error
            }
        }
    }
    data.put("parents",taxonParents);
    
	// classification for taxon ; get all the hierarchy of taxon above, and possibly
	// below of taxon, and save to hashmap and add to vector. Vector is available
	// as a sequence in .ftl
	Vector<HashMap<String,Object>> taxonClassification = new Vector<HashMap<String,Object>>();
	List<Taxon> classification = null;
	classification = TaxonManager.getClassification(taxon);
    if(classification != null){
        for(Taxon node : classification){
            HashMap<String,Object> nodeInfo = new HashMap<String,Object>();
            try{
            	nodeInfo.put("taxonId",node.getId());
                nodeInfo.put("fullScientificName",node.getLookup().getCalnamehtml());
                nodeInfo.put("fullScientificNameUrl",node.getLookup().getCalname());
                nodeInfo.put("rank",node.getRank().getRank());
                nodeInfo.put("rankId",node.getRank().getId());
                taxonClassification.add(nodeInfo);
            }
            catch(NullPointerException e){
                //drop on error
            }
        }
    }
	data.put("tree",taxonClassification);
	
	// vernacular names for taxon ; each vernacular name is saved in an hashmap
    // and all hashmap are added to a vector wich is added to the main data 
    // hashmap. That vector is available in the ftl as a sequence   	
   	Vector<HashMap<String,Object>> taxonVernacularNames = new Vector<HashMap<String,Object>>();
   	List<VernacularName> vernacularNames = null;
    vernacularNames = taxon.getVernacularnames();
    if(vernacularNames != null){
        for(VernacularName vernacularName : vernacularNames){
            try{
                HashMap<String,Object> vernacularData = new HashMap<String,Object>();
                vernacularData.put("vernacularId",vernacularName.getId());
                vernacularData.put("name",vernacularName.getName());
                vernacularData.put("status",vernacularName.getStatus().getStatus());
                vernacularData.put("language",vernacularName.getLanguage());
                vernacularData.put("reference",vernacularName.getReference().getReference());
                vernacularData.put("referenceShort",vernacularName.getReference().getReferenceshort());
                vernacularData.put("link",vernacularName.getReference().getUrl());
                taxonVernacularNames.add(vernacularData);
            }
            catch(NullPointerException e){
                //drop on error
            }
        }
    }
    data.put("vernacularNames",taxonVernacularNames);
    
    // synonyms for taxon ; each synonym is saved in an hashmap and all hashmap
    // are added to a vector wich is added to the main data hashmap. That vector
    // is available in the ftl as a sequence. The synonyms are filtered from the
    // children of the taxon by the isSynonymPredicate predicate
    Vector<HashMap<String,Object>> taxonSynonyms = new Vector<HashMap<String,Object>>();
    List<Taxon> synonyms = null;
    FilterIterator filterIterator = new FilterIterator(taxon.getChildren().iterator(),new IsSynonymPredicate());
    if(filterIterator != null){
    	while(filterIterator.hasNext()){
    		try{
	            HashMap<String,Object> synonymData = new HashMap<String,Object>();
	            Taxon synonym = (Taxon) filterIterator.next();
	            synonymData.put("taxonId",synonym.getId());
	            synonymData.put("fullScientificName",synonym.getLookup().getCalnamehtmlauthor());
	            synonymData.put("fullScientificNameUrl",synonym.getLookup().getCalname());
                synonymData.put("reference",synonym.getReference().getReference());
                synonymData.put("referenceShort",synonym.getReference().getReferenceshort());
                synonymData.put("link",synonym.getReference().getUrl());
	            taxonSynonyms.add(synonymData);
	        }
	        catch(NullPointerException e){
	            //drop on error
	            
	        }
    	}
    }
    data.put("synonyms",taxonSynonyms);
    
    // habitus (using the calculated habit from lookup)
    Vector<HashMap<String,String>> taxonHabituses = new Vector<HashMap<String,String>>();
    if(taxon.getLookup().getCalhabit() != null){
	    String[] unsplitedHabitusData = taxon.getLookup().getCalhabit().split(",");
	    if(unsplitedHabitusData != null){
			for(String habit : unsplitedHabitusData){
				HashMap<String,String> habitusData = new HashMap<String,String>();
				habitusData.put("habitus",habit);
				taxonHabituses.add(habitusData);
			}
	    }
    }
    data.put("habituses",taxonHabituses);
    
    // distribution
    Vector<HashMap<String,Object>> taxonDistributions = new Vector<HashMap<String,Object>>();
    List<Distribution> distributions;
    distributions = taxon.getDistribution();
    if(distributions != null){
        for(Distribution distribution : distributions){
        	try{
	            HashMap<String,Object> distributionData = new HashMap<String,Object>();
	            distributionData.put("province",distribution.getRegion().getRegion());
	            distributionData.put("status",distribution.getDistributionStatus().getDistributionstatus());
	            distributionData.put("excluded",distribution.getExcludedcode().getExcludedcode());
	            distributionData.put("reference",distribution.getReference().getReference());
	            distributionData.put("referenceShort",distribution.getReference().getReferenceshort());
	            distributionData.put("link",distribution.getReference().getUrl());
	            taxonDistributions.add(distributionData);
        	}
        	catch(NullPointerException e){
        		//drop on error
        		e.printStackTrace();
        	}
        }
    }
        
    boolean computedDistribution = false;
    // if taxon has no distribution information (distribution entity), display
    // distribution lookup info (distributionlookup entity) and display message
    // to user...
    if(taxonDistributions.size() == 0){
    	computedDistribution = true;
        //build a distribution hashmap and add to taxonDistributions vector
        Lookup lookup = taxon.getLookup();
        if(lookup != null)
        	taxonDistributions = TaxonManager.computeDistribution(lookup);
    }	

    data.put("computedDistribution",computedDistribution);
    data.put("distributions",taxonDistributions);

    // base information for taxon ;
    // the full scientific name, generated with html and author name
    String fullScientificName = taxon.getLookup().getCalnamehtmlauthor();
    data.put("fullScientificName",fullScientificName);

    // the full scientific name, stripped of html
    String pageTitle = taxon.getLookup().getCalnameauthor();
    data.put("pageTitle",pageTitle);
    
    // status 
    String status = "";
    if(taxon.getStatus() != null && taxon.getStatus().getStatus() != null){
    	status = taxon.getStatus().getStatus();
    	if(taxon.getStatus().getId() == ApplicationConfig.STATUS_SYNONYM)
    		isSynonymConcept = true;
    }
    data.put("status",status);
    
    // rank
    String rank = taxon.getRank().getRank();
    data.put("rank",rank);
    
    // rankid (for indentation purposes in classification tree display)
    int rankid = taxon.getRank().getId();
    data.put("rankId",rankid);
    
    // reference code
    String reference = taxon.getReference().getReference();
    data.put("reference",reference);
    
    String referenceShort = taxon.getReference().getReferenceshort();
    data.put("referenceShort",referenceShort);
    
    // reference link
    String link = taxon.getReference().getUrl();
    data.put("link",link);
    
    // is taxon is an accepted concept, verify if it's distribution image exists
    // if not, create the svg & png file. Never create a distribution image file
    // for a synonym
    String png = "";
    String svg = "";
    if(!isSynonymConcept){
        //TODO: verify image, generate it if necessary
        //write SVG file
        //TaxonManager.writeDistributionSvg(taxon);

        svg = ApplicationConfig.getGeneratedImageURL() + ApplicationConfig.SVG_FILE_PREFIX + taxon.getId() + ApplicationConfig.SVG_FILE_EXT;
        png = ApplicationConfig.getGeneratedImageURL() + ApplicationConfig.SVG_FILE_PREFIX + taxon.getId() + ApplicationConfig.PNG_FILE_EXT;
    }
    
    data.put("png",png);
    data.put("svg",svg);
    
    //Those URL will allow to open the 'Save as' dialog automaticly (client side)
    data.put("pngDownload",png+ApplicationConfig.DOWNLOAD_GENERATED_IMG_URL);
    data.put("svgDownload",svg+ApplicationConfig.DOWNLOAD_GENERATED_IMG_URL);

    // boolean synonym concept
    data.put("isSynonymConcept",isSynonymConcept);
    
    // boolean hybrid concept
    data.put("isHybridConcept",isHybridConcept);
    
    // attach data to document root
    root.put("data",data);
    
    // add extra data to page global hashmap
    _page.put("rank",LabelMappings.getRankLabel(rankid));
    _page.put("isSynonym",isSynonymConcept);
}
catch(org.hibernate.ObjectNotFoundException e){
	notFound(response);
}
catch(Exception e){
	e.printStackTrace();
    out.write("Fatal error : " + e.toString());
}
%>
<%@ include file="_inc/ftl/processStop.jsp" %>